package de.htw.praxisprojekt.algo.impl;

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;

import de.htw.praxisprojekt.AlgoData;
import de.htw.praxisprojekt.Vector2D;
import de.htw.praxisprojekt.algo.LineAlgorithm;
import de.htw.praxisprojekt.data.AlgoPoint;
import de.htw.praxisprojekt.data.draw.DrawArc;
import de.htw.praxisprojekt.data.draw.DrawLine;
import de.htw.praxisprojekt.data.draw.DrawObject;

public class JenksAlgorithm extends LineAlgorithm{

	private JSpinner dmin1;
	private JSpinner dmin2;
	private JSpinner phimax;

	@Override
	public String getAlgoName(){
		return "Jenks";
	}

	@Override
	public JPanel getOptionPane(){
		JPanel panel=super.getOptionPane();
		panel.add(new JLabel("Abstand AB"));
		panel.add(dmin1=new JSpinner(new SpinnerNumberModel(25,0.0,1000,1)));
		addChangeListenerToSpinner(dmin1);
		panel.add(new JLabel("Abstand AC"));
		panel.add(dmin2=new JSpinner(new SpinnerNumberModel(40,0.0,1000,1)));
		addChangeListenerToSpinner(dmin2);
		panel.add(new JLabel("Max Winkel \u03C6"));
		panel.add(phimax=new JSpinner(new SpinnerNumberModel(160.0,0.0,360,1)));
		addChangeListenerToSpinner(phimax);

		panel.add(new JLabel());
		panel.add(new JLabel());

		return panel;
	}

	@Override
	public void play(AlgoData algoData,int maxStepIndex){
		super.play(algoData,maxStepIndex);
		
		if(maxStepIndex == 0)
			return;
		
		List<AlgoPoint> algoPoints=algoData.getAlgoPoints();
		List<Vector2D> pointList=new ArrayList<Vector2D>();
		for(int i=0;i<algoPoints.size();i++){
			pointList.add(algoPoints.get(i).getPoint());
		}
		List<DrawObject> drawObjects=algoData.getDrawObjects();
		int s=0,r=0;
		int n=algoPoints.size()-1;
		float dmin1=((Double)this.dmin1.getValue()).floatValue()*algoData.getScaleFactor();
		float dmin2=((Double)this.dmin2.getValue()).floatValue()*algoData.getScaleFactor();
		float phimax=((Double)this.phimax.getValue()).floatValue();
		if(algoPoints.size()==0||algoPoints.size()==1)
			return;
		Vector2D activePoint=algoPoints.get(0).getPoint();
		Vector2D nextPoint=algoPoints.get(1).getPoint();
		if(algoPoints.size()==2){
			drawObjects.add(new DrawLine(activePoint,nextPoint));
			return;
		}
		Vector2D nextNextPoint=algoPoints.get(2).getPoint();
		Vector2D lastActivePoint=new Vector2D();
		Vector2D lastActiveNullPoint=new Vector2D();
		Vector2D dmin1v=new Vector2D();
		Vector2D dmin1Point=new Vector2D();
		Vector2D lastNextPoint=new Vector2D();
		Vector2D lastNextNullPoint=new Vector2D();
		Vector2D dmin2v=new Vector2D();
		Vector2D dmin2Point=new Vector2D();
		Vector2D lastPoint=new Vector2D();
		int index=0;
		while(index<algoPoints.size() - 1 && index<=maxStepIndex - 1 ){
			index++;
			float angle=Vector2D.getAngleBetween3Points(activePoint,nextPoint,nextNextPoint);
			if(activePoint.dist(nextPoint)<dmin1||activePoint.dist(nextNextPoint)<dmin2||angle>phimax){
				pointList.set(index,null);
				if(s+r+3<=n){
					lastPoint=activePoint;
					nextPoint=algoPoints.get(s+2+r).getPoint();
					nextNextPoint=algoPoints.get(s+3+r).getPoint();
					r++;
				}else{
					lastPoint=activePoint;
					activePoint=nextPoint;
					nextPoint=nextNextPoint;
				}
			}else{
				if(s+r+3<=n){
					lastPoint=activePoint;
					activePoint=nextPoint;
					nextPoint=nextNextPoint;
					nextNextPoint=algoPoints.get(s+r+3).getPoint();
					s=s+r+1;
					r=0;
				}else{
					lastPoint=activePoint;
					activePoint=nextPoint;
					nextPoint=nextNextPoint;
				}
			}
		}

		Vector2D start=pointList.get(0);
		for(int i=1;i<=index;i++){
			Vector2D end=pointList.get(i);
			if(end==null)
				continue;

			drawObjects.add(new DrawLine(start,end));
			start=end;
		}

		if(index<n){
			drawObjects.add(new DrawLine(lastPoint,algoPoints.get(index+1).getPoint()).setColor(Color.GREEN));
			Vector2D a=algoPoints.get(index-1).getPoint();
			Vector2D b=algoPoints.get(index).getPoint();
			Vector2D c=algoPoints.get(index+1).getPoint();
			float angle=Vector2D.getAngleBetween3Points(a,b,c);
			float basicAngle=b.angle(c);
			boolean isLeft=Vector2D.isPointBLeftofAC(a,b,c);
			drawObjects.add(new DrawArc(b,(int)basicAngle,isLeft?(int)angle:(int)-angle));
			drawObjects.add(new DrawArc(b,(int)basicAngle,isLeft?(int)phimax:(int)-phimax).setRadius(40).setColor(Color.BLUE));
		}
		if(index<n&&r==0){
			lastActivePoint.x=activePoint.x-lastPoint.x;
			lastActivePoint.y=activePoint.y-lastPoint.y;
			lastActiveNullPoint.x=1/(lastPoint.dist(activePoint))*lastActivePoint.x;
			lastActiveNullPoint.y=1/(lastPoint.dist(activePoint))*lastActivePoint.y;
			dmin1v.x=lastActiveNullPoint.x*dmin1;
			dmin1v.y=lastActiveNullPoint.y*dmin1;
			dmin1Point.x=lastPoint.x+dmin1v.x;
			dmin1Point.y=lastPoint.y+dmin1v.y;
			drawObjects.add(new DrawLine(lastPoint,dmin1Point).setColor(Color.RED));
			lastNextPoint.x=nextPoint.x-lastPoint.x;
			lastNextPoint.y=nextPoint.y-lastPoint.y;
			lastNextNullPoint.x=1/(lastPoint.dist(nextPoint))*lastNextPoint.x;
			lastNextNullPoint.y=1/(lastPoint.dist(nextPoint))*lastNextPoint.y;
			dmin2v.x=lastNextNullPoint.x*dmin2;
			dmin2v.y=lastNextNullPoint.y*dmin2;
			dmin2Point.x=lastPoint.x+dmin2v.x;
			dmin2Point.y=lastPoint.y+dmin2v.y;
			drawObjects.add(new DrawLine(lastPoint,dmin2Point).setColor(Color.RED));
		}
		setStepIndex(index);
	}
}